ros2_control 控制器架构与 chainable 机制
ros2_control 的源码分布在五个仓库、编译出十几个包,架构讨论里出现的角色(controller_manager、hardware_interface、chainable controller)与实际包名并不一一对应,这是读码的第一道坎。本文以 AdmittanceController(Humble 分支,commit 2105376,即 v2.54.0 之后 4 个提交、admittance_controller 代码与 2.54.0 相同)为线索,讲清三个角色各自的职责、chainable 的准确含义、角色与包的映射,以及环境实证里容易被误判的信号。适合准备读 ros2_controllers 源码或做控制器二次开发的读者。AdmittanceController 的完整源码走查见本站《AdmittanceController 源码精读与全流程走查》。
三个角色
- controller_manager:100 Hz 实时循环,读硬件 → 逐个调控制器的
update()→ 写硬件。可执行文件是ros2_control_node;ros2 controlCLI 是它的 service 客户端,服务定义在controller_manager_msgs包。 - hardware_interface:关节与传感器的具名 double 接口(state / command interfaces),控制器与硬件的唯一通道。硬件侧由
hardware_interface包定义 System / Sensor / Actuator;控制器侧基类在controller_interface包。 - chainable controller:能被串接的控制器,从
ChainableControllerInterface派生、导出 reference interfaces。AdmittanceController 导出的是 position / velocity reference interfaces。
CM 统一调度框内所有控制器;mock 硬件用一个 hardware_interface::SystemInterface 插件同时扮演力传感器和机械臂两个框。
chainable 的准确含义
一个容易搞混的点:controller_manager 管理的是「多个 controller」,chainable 是其中一部分 controller 的属性,不是 controller 的定义。三种形态(实际系统里经常在同一个 CM 中同时运行这三类):
| 控制器 | 形态 | chainable |
|---|---|---|
joint_state_broadcaster | broadcaster:只读状态、发 /joint_states 话题,观测旁路 | 否 |
joint_trajectory_controller | 普通控制器:轨迹话题进 → 关节命令出,链的源头 | 否 |
admittance_controller | 导出 reference interfaces,可被上游串接 | 是 |
两条关键性质:
- 级联数据不走 ROS 话题。JTC → AdmittanceController 的参考传递经 reference interfaces 在 CM 的同一个 update 周期内完成,CM 按链式依赖排序(先 update 上游再 update 下游),零序列化、零 DDS 往返——这是 ros2_control 里唯一保证实时性的控制器间通道。
- chainable 不等于必须被串接。AdmittanceController 保留了话题入口
/admittance_controller/joint_references,非级联模式可以直接喂关节参考。
角色 → 包的映射
| 架构角色 | 包 | 说明 |
|---|---|---|
| controller_manager | controller_manager + controller_manager_msgs | 循环本体;CLI 的服务定义 |
| hardware_interface | hardware_interface + controller_interface | 硬件侧接口;控制器侧基类(含 ChainableControllerInterface) |
| AdmittanceController 大框 | admittance_controller | AdmittanceRule 不是独立包,是包内类,实现在 admittance_rule_impl.hpp |
| JTC 框 | joint_trajectory_controller | 用 apt 版即可,无需进源码构建 |
| kinematics_interface 插件 | kinematics_interface + kinematics_interface_kdl | 前者纯虚接口,后者 KDL 实现,运行时 pluginlib 按参数加载 |
支撑包(依赖链上,图中不出现):realtime_tools(RT-safe 的 realtime buffer / publisher,AdmittanceRule 读 wrench 经它)、control_toolbox(控制数学与滤波)、control_msgs(JointTrajectory 等 JTC 话题消息)、ros2_control_test_assets + hardware_interface_testing(测试用最小假机器人资产,跑 gtest 用)、xacro / plotjuggler / python3-vcstool(工具,不在控制回路)。
仓库与包的对应(vcs import ros2_controllers.humble.repos 拉 5 个仓库,colcon build --packages-up-to admittance_controller 编出 12 个包):
ros2_control仓库 →controller_manager、hardware_interface、controller_interface、controller_manager_msgs、ros2_control_test_assets、hardware_interface_testing(6 个)ros2_controllers仓库 →admittance_controllerkinematics_interface仓库 →kinematics_interface、kinematics_interface_kdlrealtime_tools、control_toolbox、control_msgs仓库 → 各 1 个
apt 的 ros2-control / ros2-controllers 是空壳 meta 包,不含代码,作用是一条命令拉齐一组包。apt 版与源码 overlay 同名包并存时,按 AMENT_PREFIX_PATH 顺序取排在前面的,overlay 在前——这是改源码后能生效的机制。
环境实证(Ubuntu 22.04 + Humble)
- 裸启动
ros2 run controller_manager ros2_control_node,两条 WARN 均正常:'update_rate' parameter not set是没给参数文件,默认 100 Hz;FIFO RT scheduling … Operation not permitted是当前用户无实时调度特权(未配 rtprio limits),CM 退回普通调度,mock 硬件不受影响。 ros2 control list_controller_types是运行时 service 调用,CM 不在跑会一直 waiting for service——验证插件枚举必须先起一个 CM。ros2_control_node --help不打印 usage:Humble 不识别该参数,直接启动节点。- 版本:apt 安装
ros-humble-ros2-controllers2.54.0;源码 clone 的 humble 分支 HEAD 恰为2105376,与本文行号锚点同版本,无需 checkout。
要点
- 说「CM 管理多个 chainable controller」不准确,应为「CM 管理多个 controller,其中一部分是 chainable 的」;admittance_controller 属于 chainable 这一类。
- 控制器间要实时,走 reference interfaces(CM 周期内);不要求实时,走话题(如 JSB 的
/joint_states、JTC 的轨迹入口)。 - 改 AdmittanceRule 只动
admittance_controller一个包,重编用colcon build --packages-select admittance_controller。
在此架构基础上对 AdmittanceController 生命周期的逐行走查、参数系统与 mock 硬件实测中的排坑,见本站《AdmittanceController 源码精读与全流程走查》;导纳定律需要的六个坐标位姿的来历,见本站《AdmittanceTransforms 的六个位姿:导纳定律的坐标桥梁》;力控算法层面的导纳与 PI 对比,见本站《导纳控制与 PI 控制:力控算法的定位与对比》。